package org.stream.transfer;

import org.apache.log4j.net.SocketServer;

import java.io.IOException;
import java.io.Reader;
import java.net.InetSocketAddress;
import java.net.SocketOption;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ProxyServer implements Runnable {

    ServerSocketChannel serverSocketChannel;
    Selector selector;
    ExecutorService executor ;


    public ProxyServer() {
        init();
    }

    private void init(){
        executor= Executors.newFixedThreadPool(Config.getInteger("threads",5));
        try {
            selector=Selector.open();
            serverSocketChannel=ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.socket().bind(new InetSocketAddress(Config.getInteger("listener_port",8093)));
            serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    public void start(){
        executor.execute(this);
    }


    @Override
    public void run() {
        System.out.println("启动");
        while (true){
            try {
                int c=selector.selectNow();
                //System.out.println("C="+c);
                if(c==0) {
                    Thread.yield();
                    continue;
                }
                //System.out.println("C="+c);
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> it = selectionKeys.iterator();
                System.out.println(selectionKeys);
                while (it.hasNext()){
                    SelectionKey next = it.next();
                    it.remove();
                    System.out.println("next.isValid = "+next.isValid());
                    if(next.isValid()){
                        if(next.isAcceptable()){
                            doAccept(next);
                        }else{
                            Transfer transfer= (Transfer) next.attachment();
                            try {
                                if( next.isReadable()){

                                   transfer.doRead(next);

                                }else if(next.isConnectable()){
                                    transfer.onConnect(selector);
                                }
                            }catch (Exception e){
                                e.printStackTrace();
                                transfer.close();
                            }

                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void doAccept(SelectionKey selectionKey) throws IOException {
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
        SocketChannel socketChannel;
        while((socketChannel = serverSocketChannel.accept()) != null) {
            System.out.println("有新的连接: "+socketChannel.socket().getInetAddress());
            try {
                socketChannel.configureBlocking(false);
                socketChannel.socket().setTcpNoDelay(true);
                socketChannel.socket().setKeepAlive(true);
                Transfer transfer=new Transfer(socketChannel);
                executor.execute(()-> {
                        transfer.register(selector);
                        System.out.println("注册新连接成功!");
                    }
                );

            } catch (IOException e) {
                socketChannel.close();
                throw e;
            }

        }
    }


}
